# include"mythread.hpp"
# include<vector>
#include"Mutex.hpp"

// 将抢票代码做线程互斥，也就是加锁

class ThreadDate
{
public:
    // 当结构体用，直接公开成员。当然也可以private，然后写对应的get set接口
    std::string _name;
    pthread_mutex_t* _mutex_p; // 对锁这个类型的指针 

    ThreadDate(const std::string& name, pthread_mutex_t* mutex_p)
    :_name(name)
    ,_mutex_p(mutex_p)
    {}

    ~ThreadDate(){}
};

// 直接变成全局锁, 静态初始化
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 
int tickets = 1000;
void* GetTicket(void* args)
{
    // ThreadDate* td = static_cast<ThreadDate*>(args);
    const char* name = static_cast<const char*>(args);

    while(true)
    {
        // pthread_mutex_lock(td->_mutex_p); // 加锁, 动态分配
        // pthread_mutex_lock(&lock); // 加锁，静态分配
        
        { //这里是套一个作用域，控制析构函数的调用时间，即——控制临界区范围
        MutexGuard mutexGuard(&lock); // 使用自己封装的类型进行加锁————这个风格叫RAII风格
        // 这里要注意，锁只规定了线程会互斥访问临界资源，并没有规定那个线程先执行
        // 锁是多个线程执行流竞争的
        if(tickets > 0)
        {
            //还有票可以抢
            usleep(12345); // 这里大概是0.01s
            // 1s = 1000ms = 1000000微秒 这里usleep的单位是微秒
            // std::cout << td->_name << "正在进行抢票: " << tickets-- << std::endl;
            std::cout << name << "正在进行抢票: " << tickets-- << std::endl;
            // pthread_mutex_unlock(td->_mutex_p); // 解锁，加锁区域是临界区
            // pthread_mutex_unlock(&lock); // 解锁，加锁区域是临界区
        }
        else
        {
            // 这里也要解锁的原因是，加锁是在条件判断之前加的，一旦进入else，就无法解锁
            // pthread_mutex_unlock(td->_mutex_p); // 解锁
            // pthread_mutex_unlock(&lock); // 解锁
            break;
        }
        }
        // 抢完票，还要对抢完票的信息进行汇总，然后给用户显示出来
        //这里用一个usleep来模拟这个汇总并显示的工作
        usleep(12345);
    }


    return nullptr;
}


int main()
{
// #define NUM 4
//     // 创建锁并初始化
//     pthread_mutex_t lock; // 除了在局部创建锁，也可以把锁定义成全局的
//     pthread_mutex_init(&lock, nullptr);

//     // 创建线程
//     std::vector<pthread_t> tids(NUM);
//     for(int i = 0; i < NUM; i++)
//     {
//         char buffer[64];
//         snprintf(buffer, sizeof buffer, "thread %d", i+1);
//         ThreadDate* td = new ThreadDate(buffer, &lock);
//         pthread_create(&tids[i], nullptr, GetTicket, (void*)td);
//     }

//     // 线程等待
//     for(auto& tid : tids)
//     {
//         pthread_join(tid, nullptr);
//     }
    
//     pthread_mutex_destroy(&lock); // 销毁锁

    // 使用全局锁，不需要代码中调用初始化和销毁锁的接口
    pthread_t t1,t2,t3,t4;
    pthread_create(&t1, nullptr, GetTicket, (void*) "thread 1");
    pthread_create(&t2, nullptr, GetTicket, (void*) "thread 2");
    pthread_create(&t3, nullptr, GetTicket, (void*) "thread 3");
    pthread_create(&t4, nullptr, GetTicket, (void*) "thread 4");

    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);
    pthread_join(t3, nullptr);
    pthread_join(t4, nullptr);

    return 0;
}